﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace CPPEI.Coolzon.UI.ActiveXPartLib
{
    /// <summary>
    /// 程序信息
    /// </summary>
    public class SingletonINSVideoPro : IExeService
    {
        #region 进程通讯命名管道
        public string PipeName { get; set; }
        public NamedPipeClientStream PipeClient { get; set; }
        public StreamWriter PipeClientStreamWriter { get; set; }
        public NamedPipeServerStream PipeServer { get; set; }
        public StreamReader PipeServerStreamReader { get; set; }
        #endregion

        public Process Process { get; set; }

        public string Name { get; set; }

        /// <summary>
        /// 窗口句柄
        /// </summary>
        private List<INSVideoWindow> _windows = new List<INSVideoWindow>();

        public event Action<string, string, IntPtr> Opened;

        private SingletonINSVideoPro()
        {
        }

        private static object s_lockObj = new object();
        private static SingletonINSVideoPro s_instance;
        public static SingletonINSVideoPro Start()
        {
            if (s_instance == null)
            {
                lock (s_lockObj)
                {

                    if (s_instance == null)
                    {
                        s_instance = new SingletonINSVideoPro();
                        
                        // 注册到exe程序服务中
                        ExeServiceManager.Register(s_instance);

                        s_instance.Run();
                    }
                }
                // 启动视频程序
                return s_instance;
            }
            else
            {
                return s_instance;
            }
        }

        private bool Run()
        {
            CPPEI.Coolzon.Common.Logger.InfoToTag("ActiveXPartLib", "SingletonINSVideoPro.Run");

            // 查找是否具有程序了，如果有就删除掉
            string programName = "CPPEI.Coolzon.Tools.INSVideoTool";
            string programFile = string.Format("{0}\\tools\\INSVideo\\CPPEI.Coolzon.Tools.INSVideoTool.exe", AppDomain.CurrentDomain.BaseDirectory);
            string pipeName = string.Format("p{0}", Guid.NewGuid().ToString("N"));

            Process[] oldProcessArr = Process.GetProcessesByName(programName);
            if(oldProcessArr!=null && oldProcessArr.Length > 0)
            {
                for (int index = 0; index < oldProcessArr.Length; index++)
                {
                    try
                    {
                        oldProcessArr[index].Kill();

                        CPPEI.Coolzon.Common.Logger.InfoToTag("ActiveXPartLib", string.Format("SingletonINSVideoPro kill process:{0}", oldProcessArr[index].Id));
                    }
                    catch(Exception ex)
                    {

                        CPPEI.Coolzon.Common.Logger.ErrorToTag("ActiveXPartLib", string.Format("SingletonINSVideoPro kill process:{0} error,ex:{1}", oldProcessArr[index].Id, ex));
                    }
                }
            }

            ProcessStartInfo info = new ProcessStartInfo();
            info.FileName = programFile;
            info.Arguments = pipeName;
            try
            {
                this.Process = Process.Start(info);
                if (this.Process == null)
                {
                    Common.Logger.ErrorToTag("ActiveXPartLib", "启动外部程序失败,program:{0}, file:{1}, arguments:{2}", programName, programFile, pipeName);
                    return false;
                }
                this.Name = programName;
            }
            catch (Exception ex)
            {
                Common.Logger.ErrorToTag("ActiveXPartLib", "启动外部程序失败,program:{0}, file:{1}, arguments:{2}, ex:{3}", programName, programFile, pipeName, ex);
                return false;
            }
            Common.Logger.DebugToTag("ActiveXPartLib", "启动外部程序,program:{0}, file:{1}, arguments:{2}", programName, programFile, pipeName);

            try
            {
                // 建立命名管道
                this.PipeName = pipeName;

                this.PipeServer = new NamedPipeServerStream(string.Format("{0}AD", pipeName),
                    PipeDirection.In,
                    1,
                    PipeTransmissionMode.Message,
                    PipeOptions.Asynchronous);

                ThreadPool.QueueUserWorkItem(Running);

                this.PipeClient = new NamedPipeClientStream("127.0.0.1", string.Format("{0}DA", pipeName), PipeDirection.Out);

                this.PipeClient.Connect(1000);
                this.PipeClientStreamWriter = new StreamWriter(this.PipeClient);
                this.PipeClientStreamWriter.AutoFlush = true;
                Common.Logger.DebugToTag("ActiveXPartLib", string.Format("命名管道{0}连接成功", this.PipeName));
            }
            catch (Exception ex)
            {
                Common.Logger.DebugToTag("ActiveXPartLib", string.Format("命名管道{0}连接失败,ex:{1}", this.PipeName, ex));
                this.PipeClientStreamWriter.Close();
                this.PipeClientStreamWriter = null;
                this.PipeClient.Close();
                this.PipeClient = null;
                return false;
            }
            return true;
        }

        private void Running(object state)
        {
            this.PipeServer.BeginWaitForConnection((o) =>
            {
                NamedPipeServerStream server = (NamedPipeServerStream)o.AsyncState;
                server.EndWaitForConnection(o);
                this.PipeServerStreamReader = new StreamReader(server);
                string result = null;
                string clientName = server.GetImpersonationUserName();
                while (true)
                {
                    try
                    {
                        result = this.PipeServerStreamReader.ReadLine();
                    }
                    catch (Exception ex)
                    {
                        Common.Logger.ErrorToTag("ActiveXPartLib", string.Format(" s_pro.PipeServerStreamReader.ReadLine出错,ex:{0}", ex));
                        result = string.Empty;
                    }
                    if (result == null || result == "exit")
                    {
                        break;
                    }
                    string[] segments = result.Split(new string[] { ":>" }, StringSplitOptions.RemoveEmptyEntries);
                    if (segments.Length > 0)
                    {
                        Common.Logger.DebugToTag("ActiveXPartLib", string.Format(" s_pro.PipeServer-running:{0}", result));
                        if (string.Equals(segments[0], "opencamera", StringComparison.CurrentCultureIgnoreCase))
                        {
                            string[] pArr = segments[1].Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
                            string partName = pArr[0];
                            IntPtr hwnd = new IntPtr(Convert.ToInt32(pArr[1]));
                            this.ReceiveOpen(partName, hwnd);
                        }
                    }
                }
                if (this.PipeServerStreamReader != null)
                {
                    this.PipeServerStreamReader.Close();
                    this.PipeServerStreamReader = null;
                }
                if (this.PipeServer != null)
                {
                    this.PipeServer.Close();
                    this.PipeServer = null;
                }
            }, this.PipeServer);
        }

        /// <summary>
        /// 打开摄像头
        /// </summary>
        /// <param name="url"></param>
        /// <param name="user"></param>
        /// <param name="pwd"></param>
        /// <param name="camera"></param>
        /// <param name="loginClientStrategy"></param>
        /// <param name="localVideoFileName"></param>
        public void OpenCamera(string url, string user, string pwd, int camera, string loginClientStrategy,
            string localVideoFileName, string partName, string scene)
        {
            for (int index = 0; index < _windows.Count; index++)
            {
                if (string.Equals(_windows[index].Part, partName) && string.Equals(_windows[index].Scene, scene))
                {
                    // 存在
                    Common.Logger.DebugToTag("ActiveXPartLib", "窗口已经打开");
                    // 已经打开
                    if (this.Opened != null)
                    {
                        this.Opened(_windows[index].Scene, partName, _windows[index].Hwnd);
                    }
                    return;
                }
            }
            string cmdString = string.Format("opencamera:>{0},{1},{2},{3},{4},{5},{6}-{7}",
                url,
                user,
                pwd,
                camera,
                loginClientStrategy,
                localVideoFileName,
                scene,
                partName);
            Common.Logger.DebugToTag("ActiveXPartLib", string.Format("发送指令{0}", cmdString));
            if (PipeClientStreamWriter != null)
            {
                PipeClientStreamWriter.WriteLine(cmdString);
            }
        }

        /// <summary>
        /// 切换摄像头
        /// </summary>
        /// <param name="hwnd"></param>
        /// <param name="camera"></param>
        public void SetCamera(IntPtr hwnd, int camera)
        {
            string cmdString = string.Format("setcamera:>{0},{1}",
                hwnd,
                camera);
            Common.Logger.DebugToTag("ActiveXPartLib", string.Format("发送指令{0}", cmdString));
            if (PipeClientStreamWriter != null)
            {
                PipeClientStreamWriter.WriteLine(cmdString);
            }
        }

        public void CloseCameraWindow(string scene, string part)
        {
            IntPtr hwnd = IntPtr.Zero;
            for (int index = 0; index < _windows.Count; index++)
            {
                if (_windows[index].Scene == scene && _windows[index].Part == part)
                {
                    hwnd = _windows[index].Hwnd;
                    break;
                }
            }

            if (hwnd != IntPtr.Zero)
            {
                CloseCamera(hwnd);
            }
        }

        /// <summary>
        /// 关闭
        /// </summary>
        /// <param name="hwnd"></param>
        public void CloseCamera(IntPtr hwnd)
        {
            for (int index = 0; index < _windows.Count; index++)
            {
                if (_windows[index].Hwnd == hwnd)
                {
                    _windows.RemoveAt(index);
                    break;
                }
            }

            string cmdString = string.Format("closecamera:>{0}",
                hwnd);
            Common.Logger.DebugToTag("ActiveXPartLib", string.Format("发送指令{0}", cmdString));
            if (PipeClientStreamWriter != null)
            {
                try
                {
                    PipeClientStreamWriter.WriteLine(cmdString);
                }
                catch (Exception ex)
                {
                    Common.Logger.DebugToTag("ActiveXPartLib", string.Format("发送指令{0},出错,ex:{1}", cmdString, ex));
                }
            }
        }

        private void ReceiveOpen(string partName, IntPtr hwnd)
        {
            string[] arr = partName.Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries);

            INSVideoWindow window = new INSVideoWindow();
            window.Scene = arr[0];
            window.Part = arr[1];
            window.Hwnd = hwnd;
            _windows.Add(window);

            if (this.Opened != null)
            {
                this.Opened(arr[0], arr[1], hwnd);
            }
        }

        public void Release()
        {
            CPPEI.Coolzon.Common.Logger.InfoToTag("ActiveXPartLib", "SingletonINSVideoPro release");
            if(Process!=null)
            {
                try
                {
                    Process.Kill();
                }
                catch(Exception ex)
                {

                }

                try
                {
                    PipeClient.Close();
                    PipeClient = null;
                }
                catch (Exception ex)
                {

                }

                try
                {
                    PipeServer.Close();
                    PipeServer = null;
                }
                catch (Exception ex)
                {

                }
            }
        }
    }
}
